﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using System.Xml;
using System.IO;
using SPSource.Field;

namespace SPSource
{
    public class ContentTypeManager
    {
        private SPSourceFileInfo _spSourceFileInfo;

        private FieldManager _fieldManager;

        public ContentTypeManager(SPSourceFileInfo spSourceFileInfo)
        {
            _spSourceFileInfo = spSourceFileInfo;
            _fieldManager = new FieldManager(spSourceFileInfo);
        }

        public void GetContentType(XmlNode contentType)
        {
            try
            {
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    using (SPSite site = new SPSite(_spSourceFileInfo.DesignSiteUrl))
                    {
                        using (SPWeb web = site.OpenWeb())
                        {
                            string ctName = contentType.Attributes["Name"].Value;
                            SPContentType sourceCT = web.ContentTypes[ctName];
                            
                            if (sourceCT == null)
                            {
                                Utility.WriteMessage("Content Type does not existing in site!");
                            }
                            else
                            {
                                Utility.WriteMessage("Reverse engineering content type: " + ctName);

                                XmlDocument ctDocument = new XmlDocument();
                                XmlDocument columnDocument = new XmlDocument();

                                XmlNode ctRootNode = ctDocument.CreateElement("Elements");
                                XmlNode colRootNode = columnDocument.CreateElement("Elements");
                                ctDocument.AppendChild(ctRootNode);
                                columnDocument.AppendChild(colRootNode);

                                XmlAttribute contentTypeAttribute;
                                XmlNode contentTypeNode = ctDocument.CreateElement("ContentType");
                                // ID
                                contentTypeAttribute = ctDocument.CreateAttribute("ID");
                                contentTypeAttribute.Value = sourceCT.Id.ToString();
                                contentTypeNode.Attributes.Append(contentTypeAttribute);

                                // name
                                contentTypeAttribute = ctDocument.CreateAttribute("Name");
                                contentTypeAttribute.Value = sourceCT.Name;
                                contentTypeNode.Attributes.Append(contentTypeAttribute);

                                // Description
                                if (!string.IsNullOrEmpty(sourceCT.Description))
                                {
                                    contentTypeAttribute = ctDocument.CreateAttribute("Description");
                                    contentTypeAttribute.Value = sourceCT.Description;
                                    contentTypeNode.Attributes.Append(contentTypeAttribute);
                                }

                                // group
                                contentTypeAttribute = ctDocument.CreateAttribute("Group");
                                contentTypeAttribute.Value = sourceCT.Group;
                                contentTypeNode.Attributes.Append(contentTypeAttribute);

                                // sealed
                                if (sourceCT.Sealed)
                                {
                                    contentTypeAttribute = ctDocument.CreateAttribute("Sealed");
                                    contentTypeAttribute.Value = sourceCT.Sealed.ToString();
                                    contentTypeNode.Attributes.Append(contentTypeAttribute);
                                }

                                // hidden
                                if (sourceCT.Hidden)
                                {
                                    contentTypeAttribute = ctDocument.CreateAttribute("Hidden");
                                    contentTypeAttribute.Value = sourceCT.Hidden.ToString();
                                    contentTypeNode.Attributes.Append(contentTypeAttribute);
                                }

                                // ReadOnly
                                if (sourceCT.ReadOnly)
                                {
                                    contentTypeAttribute = ctDocument.CreateAttribute("ReadOnly");
                                    contentTypeAttribute.Value = sourceCT.ReadOnly.ToString();
                                    contentTypeNode.Attributes.Append(contentTypeAttribute);
                                }

                                SPFieldLinkCollection fieldLinks = sourceCT.FieldLinks;
                                SPContentType parentCT = sourceCT.Parent;

                                XmlNode fieldRefs = ctDocument.CreateElement("FieldRefs");

                                foreach (SPFieldLink sourceFieldLink in sourceCT.FieldLinks)
                                {
                                    string sourceSchema = string.Empty;

                                    if (parentCT.Fields.ContainsField(sourceFieldLink.Name))
                                        continue;

                                    sourceSchema = sourceFieldLink.SchemaXml;
                                    fieldRefs.InnerXml += sourceSchema;

                                    foreach(SPField field in sourceCT.Fields)
                                    {
                                        if (field.Id == sourceFieldLink.Id)
                                        {
                                            _fieldManager.GenerateFieldXml(field, colRootNode);
                                        }
                                    }
                                }

                                contentTypeNode.AppendChild(fieldRefs);
                                ctRootNode.AppendChild(contentTypeNode);

                                XmlNodeList feildRefFields = ctDocument.SelectNodes("//FieldRef");
                                _fieldManager.removeUneededAttributes(feildRefFields);

                                XmlAttribute ctNameSpace = ctDocument.CreateAttribute("xmlns");
                                ctNameSpace.Value = Constants.SharePointXmlNamespace;
                                ctRootNode.Attributes.Append(ctNameSpace);

                                XmlAttribute colNameSpace = columnDocument.CreateAttribute("xmlns");
                                colNameSpace.Value = Constants.SharePointXmlNamespace;
                                colRootNode.Attributes.Append(colNameSpace);

                                string sourceCTName = sourceCT.Name.Replace(" ", "");
                                string ctFileName = sourceCTName + ".CT.xml";
                                string ctColumnFileName = sourceCTName + ".CT.Columns.xml";

                                ctDocument.Save(_spSourceFileInfo.SPSourceFileDirectoryInfo.FullName + "\\" + ctFileName);
                                columnDocument.Save(_spSourceFileInfo.SPSourceFileDirectoryInfo.FullName + "\\" + ctColumnFileName);

                                if (!_spSourceFileInfo.OverrideFeatureDirectoryCheck)
                                {
                                    FeatureManager.AddElementManifestToFeature(
                                        new FileInfo(_spSourceFileInfo.SPSourceFileDirectoryInfo.FullName + "\\" + ctFileName));
                                    FeatureManager.AddElementManifestToFeature(
                                        new FileInfo(_spSourceFileInfo.SPSourceFileDirectoryInfo.FullName + "\\" + ctColumnFileName));
                                }
                            }
                        }
                    }
                });
            }
            catch (Exception ex)
            {
                Utility.WriteError(ex.ToString());
                throw;
            }
        }
    }
}
